// src/lexer.rs

use crate::tokens::{Token, TokenType};

pub struct Lexer {
    source: Vec<char>,  // 将字符串转换为字符向量，便于索引
    tokens: Vec<Token>, // 解析后生成的 Token 列表
    start: usize,       // 当前正在解析的词素的起始索引
    current: usize,     // 当前正在查看的字符的索引
    line: usize,        // 当前所在行
    has_error: bool,
}

impl Lexer {
    pub fn new(source_code: &str) -> Self {
        Self {
            source: source_code.chars().collect(), // 将 String 转化为 Vec<char>
            tokens: Vec::new(),
            start: 0,
            current: 0,
            line: 1,
            has_error: false,
        }
    }

    // 核心方法：扫描所有 Token，直到源代码结束
    pub fn scan_tokens(&mut self) -> &Vec<Token> {
        while !self.is_at_end() {
            // 我们正在开始解析一个新的词素
            self.start = self.current;
            self.scan_token();
        }

        if self.has_error {
            std::process::exit(1);
        }

        // 添加一个 EOF Token 表示结束
        // self.tokens
        //     .push(Token::new(TokenType::Eof, "".to_string(), self.line));
        &self.tokens
    }


    // 判断是否到达源代码末尾
    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    // 核心方法：解析单个 Token
    fn scan_token(&mut self) {
        let c = self.advance(); // 消耗并返回下一个字符
        match c {
            // 处理单字符 Token
            '(' => self.add_token(TokenType::L_PAREN),
            ')' => self.add_token(TokenType::R_PAREN),
            '{' => self.add_token(TokenType::L_BRACE),
            '}' => self.add_token(TokenType::R_BRACE),
            '[' => self.add_token(TokenType::L_BRACKT),
            ']' => self.add_token(TokenType::R_BRACKT),
            ',' => self.add_token(TokenType::COMMA),
            '.' => self.add_token(TokenType::DOT),
            '-' => self.add_token(TokenType::MINUS),
            '+' => self.add_token(TokenType::PLUS),
            ';' => self.add_token(TokenType::SEMICOLON),
            '*' => self.add_token(TokenType::MUL),
            '%' => self.add_token(TokenType::MOD),

            // 处理可能是单字符也可能是双字符的 Token (如 !=, ==)
            '!' => {
                let token_type = if self.match_char('=') {
                    TokenType::NEQ
                } else {
                    TokenType::NOT
                };
                self.add_token(token_type);
            }
            '=' => {
                let token_type = if self.match_char('=') {
                    TokenType::EQ
                } else {
                    TokenType::ASSIGN
                };
                self.add_token(token_type);
            }
            '<' => {
                let token_type = if self.match_char('=') {
                    TokenType::LE
                } else {
                    TokenType::LT
                };
                self.add_token(token_type);
            }
            '>' => {
                let token_type = if self.match_char('=') {
                    TokenType::GE
                } else {
                    TokenType::GT
                };
                self.add_token(token_type);
            }

            // 处理注释和除法符 `/`
            // 在 scan_token 方法中，修改处理 '/' 的分支
            // 处理注释和除法符 `/`
            '/' => {
                if self.match_char('/') {
                    // 遇到 `//`，单行注释直到行尾
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    // 注释内容直接丢弃，不生成 Token
                } else if self.match_char('*') {
                    // 遇到 `/*`，多行注释直到遇到 `*/`
                    self.multiline_comment();
                } else {
                    self.add_token(TokenType::DIV);
                }
            }

            // 处理空白字符：忽略，但换行符要增加行号
            ' ' | '\r' | '\t' => {}
            '\n' => {
                self.line += 1;
            }

            // 处理字符串字面量
            '"' => self.string(),

            // 处理数字字面量
            c if Self::is_digit(c) => self.number(),

            // 处理标识符和关键字
            c if Self::is_alpha(c) => self.identifier(),

            // 默认情况：无法识别的字符，报告错误
            _ => {
                self.has_error = true;
                eprintln!("Error type A at Line {}: Mysterious character \"{}\".", self.line, c);
            }
        }
    }

    // 辅助方法：消耗当前字符并返回它
    fn advance(&mut self) -> char {
        let c = self.source[self.current];
        self.current += 1;
        c
    }

    // 辅助方法：查看下一个字符，但不消耗它（Lookahead）
    fn peek(&self) -> char {
        if self.is_at_end() {
            '\0'
        } else {
            self.source[self.current]
        }
    }

    // 辅助方法：条件性地消耗下一个字符（如果匹配）
    // 例如，当前是 `!`，看看下一个是不是 `=` 来决定是 `!=` 还是 `!`
    fn match_char(&mut self, expected: char) -> bool {
        if self.is_at_end() || self.source[self.current] != expected {
            return false;
        }
        self.current += 1; // 匹配成功，消耗掉这个字符
        true
    }

    // 辅助方法：根据当前类型，获取 start 到 current 之间的字符串，并生成一个 Token 加入列表
    fn add_token(&mut self, token_type: TokenType) {
        let text: String = self.source[self.start..self.current].iter().collect();
        self.tokens.push(Token::new(token_type, text, self.line));
    }

    // 处理字符串字面量
    fn string(&mut self) {
        // 持续读取，直到遇到下一个双引号 `"`
        while self.peek() != '"' && !self.is_at_end() {
            if self.peek() == '\n' {
                self.line += 1; // 字符串可以跨行
            }
            self.advance();
        }

        if self.is_at_end() {
            eprintln!("[line {}] Error: Unterminated string.", self.line);
            return;
        }

        // 消耗掉结尾的 `"`
        self.advance();

        // 提取字符串值，去掉两边的引号
        // start 指向开始的 `"`，current 指向结束的 `"` 之后的位置
        let value: String = self.source[self.start + 1..self.current - 1]
            .iter()
            .collect();
        self.add_token(TokenType::String(value));
    }

    // 判断字符是否为数字
    fn is_digit(c: char) -> bool {
        c >= '0' && c <= '9'
    }

    // 在 lexer.rs 中修改 number() 方法

    // 处理数字字面量
    fn number(&mut self) {
        // 检查是否为十六进制 (0x 或 0X 开头)
        if self.peek() == 'x' || self.peek() == 'X' {
            self.advance(); // 消耗 'x' 或 'X'
            self.hexadecimal();
            return;
        }

        // 检查是否为八进制 (0开头且后面跟着0-7)
        // 这里故意不向后查看，08解析为0和8
        if self.source[self.start] == '0' {//} && self.peek().is_digit(8) {
            self.octal();
            return;
        }

        // 否则按十进制处理
        self.decimal();
    }

    // 处理十进制数字
    fn decimal(&mut self) {
        // 读取整数部分
        while Self::is_digit(self.peek()) {
            self.advance();
        }

        // 查看小数部分
        if self.peek() == '.' && Self::is_digit(self.peek_next()) {
            // 消耗掉小数点 `.`
            self.advance();

            // 读取小数部分
            while Self::is_digit(self.peek()) {
                self.advance();
            }
        }

        // 将捕获的数字字符串转换为 f64
        let num_str: String = self.source[self.start..self.current].iter().collect();
        let value: f64 = num_str.parse().unwrap();
        self.add_token(TokenType::INTEGER_CONST(value));
    }

    // 在 hexadecimal() 方法中添加更详细的错误检查
    fn hexadecimal(&mut self) {
        // 检查是否有有效的十六进制数字
        if !Self::is_hex_digit(self.peek()) {
            eprintln!(
                "[line {}] Error: Hexadecimal number must have at least one digit",
                self.line
            );
            self.add_token(TokenType::INTEGER_CONST(0.0));
            return;
        }

        // 读取十六进制数字
        while Self::is_hex_digit(self.peek()) {
            self.advance();
        }

        // 提取十六进制字符串
        let hex_str: String = self.source[self.start + 2..self.current].iter().collect();

        // 将十六进制字符串转换为十进制数值
        match u64::from_str_radix(&hex_str, 16) {
            Ok(value) => self.add_token(TokenType::INTEGER_CONST(value as f64)),
            Err(_) => {
                eprintln!(
                    "[line {}] Error: Invalid hexadecimal number '0x{}'",
                    self.line, hex_str
                );
                self.add_token(TokenType::INTEGER_CONST(0.0));
            }
        }
    }

    // 类似地，可以改进 octal() 方法的错误处理
    fn octal(&mut self) {
        // 读取八进制数字
        while Self::is_octal_digit(self.peek()) {
            self.advance();
        }

        // 检查是否有非八进制数字
        // if self.peek().is_ascii_digit() {
        //     // 8或9
        //     let invalid_char = self.peek();
        //     eprintln!(
        //         "[line {}] Error: Invalid octal digit '{}'",
        //         self.line, invalid_char
        //     );
        //     // 继续读取直到非数字字符
        //     while self.peek().is_ascii_digit() {
        //         self.advance();
        //     }
        // }

        // 提取八进制字符串
        let oct_str: String = self.source[self.start..self.current].iter().collect();

        // 将八进制字符串转换为十进制数值
        match u64::from_str_radix(&oct_str, 8) {
            Ok(value) => self.add_token(TokenType::INTEGER_CONST(value as f64)),
            Err(_) => {
                eprintln!(
                    "[line {}] Error: Invalid octal number '{}'",
                    self.line, oct_str
                );
                self.add_token(TokenType::INTEGER_CONST(0.0));
            }
        }
    }

    // 判断字符是否为十六进制数字
    fn is_hex_digit(c: char) -> bool {
        c.is_ascii_digit() || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')
    }

    // 判断字符是否为八进制数字
    fn is_octal_digit(c: char) -> bool {
        c >= '0' && c <= '7'
    }

    // 查看下下一个字符（用于判断 `123.` 后面是否跟着数字）
    fn peek_next(&self) -> char {
        if self.current + 1 >= self.source.len() {
            '\0'
        } else {
            self.source[self.current + 1]
        }
    }

    // 判断字符是否为字母或下划线
    fn is_alpha(c: char) -> bool {
        (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
    }

    // 判断字符是否为字母、数字或下划线（用于标识符）
    fn is_alpha_numeric(c: char) -> bool {
        Self::is_alpha(c) || Self::is_digit(c)
    }

    // 处理标识符和关键字
    fn identifier(&mut self) {
        while Self::is_alpha_numeric(self.peek()) {
            self.advance();
        }

        // 获取标识符的文本
        let text: String = self.source[self.start..self.current].iter().collect();

        // 检查它是否是关键字
        let token_type = match text.as_str() {
            "int" => TokenType::INT,
            "if" => TokenType::IF,
            "const" => TokenType::CONST,
            "void" => TokenType::VOID,
            // "for" => TokenType::For,
            "else" => TokenType::ELSE,
            "break" => TokenType::BREAK,
            "continue" => TokenType::CONTINUE,
            // "or" => TokenType::Or,
            // "print" => TokenType::Print,
            "return" => TokenType::RETURN,
            // "super" => TokenType::Super,
            // "this" => TokenType::This,
            // "true" => TokenType::True,
            // "var" => TokenType::Var,
            "while" => TokenType::WHILE,
            _ => TokenType::IDENT, // 不是关键字，就是普通标识符
        };

        self.add_token(token_type);
    }

    // 处理多行注释 /* ... */
    fn multiline_comment(&mut self) {
        // 循环直到找到注释结束标记 */
        while !self.is_at_end() {
            let c = self.advance();

            if c == '*' && self.peek() == '/' {
                // 找到注释结束标记 '*/'，消耗掉它并退出
                self.advance(); // 消耗 '/'
                return;
            } else if c == '\n' {
                // 遇到换行，增加行号
                self.line += 1;
            }
            // 如果是其他字符，继续循环（跳过）
        }

        // 如果执行到这里，说明到达文件末尾但注释仍未结束
        eprintln!(
            "[line {}] Error: Unterminated multiline comment.",
            self.line
        );
    }
    
    
}
